﻿#ifndef SPECTROGRAMVIEW_H
#define SPECTROGRAMVIEW_H

#include <QMap>
#include <QMutex>
#include <QOpenGLWidget>
#include <QQueue>
#include "thread"
using namespace std;

/**
 * @brief The SpectrogramParam struct 语谱图配置
 */
struct AudioFileParam{
    char filePath[512];
    //播放器相关参数
    uint16_t headerLen;//文件头长度
    uint64_t fileDataSize;//文件数据长度
    uint32_t sampleRate;//采样率
    uint16_t channleNumber;//通道数量
    uint16_t bitsPerSample;//采样位数
    void setFilePath(string str){
        memset(filePath,0,512);
        memcpy(filePath,str.c_str(),str.length() < 512 ? str.length() : 512);
    }
    AudioFileParam(){}
    AudioFileParam(string m_filePath,uint16_t m_headerLen,uint64_t m_fileDataSize,uint32_t m_sampleRate,uint16_t m_channleNumber,uint16_t m_bitsPerSample){
        setFilePath(m_filePath);
        headerLen = m_headerLen;//文件头长度
        fileDataSize = m_fileDataSize;//文件数据长度
        sampleRate = m_sampleRate;//采样率
        channleNumber = m_channleNumber;//通道数量
        bitsPerSample = m_bitsPerSample;//采样位数
    }
};

struct MarkBand{
    double startX;
    double stopX;
    MarkBand(){

    }
    MarkBand(double startVal,double stopVal){
        startX = startVal;
        stopX = stopVal;
    }
};

class SpectrogramView : public QOpenGLWidget
{
    Q_OBJECT
public:
    explicit SpectrogramView(QWidget *parent = nullptr);
    ~SpectrogramView();
    double getMaxX() const;
    void setMaxX(double value);

    double getMinX() const;
    void setMinX(double value);

     void setRangeX(double minX,double maxX);
     void setSelectRangeX(double minX,double maxX);

    double getShowMinX() const;
    void setShowMinX(double value);

    double getShowMaxX() const;
    void setShowMaxX(double value);

    void setMarkLineX(double value);

    void setFftLen(int value);

    void setLevelRange(int minLevel,int maxLevel);

    void drawSpectrogramView(int index,QVector<short> fftData);
    void drawErrorText();
public slots:
	void slot_update();
    void slot_drawing(bool b);
signals:
	void signal_update();
    void signal_drawing(bool b);
    void signal_changeSelectState(bool b);
    void signal_changeSelectRange(double selectMinX,double selectMaxX);
private:
    int toppadding;
    int leftpadding;
    int rightpadding;
    int bottompadding;
    //颜色设置
    QColor backColor;
    //视图区域
    QRect viewRect;
    QRect xRect;
    void reSizeRect();
    QColor lineColor;
    //X轴
    double minX;
    double maxX;
    double minShowRangeX;//最小显示范围
    double maxShowRangeX;//最大显示范围
    double showMinX;
    double showMaxX;
    double singleStepX;//步进
    int lineNumX;//线数量
    QString valuePostfixX;//后缀
    int precX;//保留小数位
    QColor valueColorX;//标志颜色
    QFont valueFontX;//内容字体

    //语谱图片
    bool setleveled;//设置能量范围完成
    int minLevel;
    int maxLevel;

    int fftLen;
    QMutex fullImgMutex;
    QImage fullImage;
    QImage tempFullImage;

    QList<QColor> colorList;
    QMap<double,QColor> colorMap;
    //框选
    bool moveSelectX;
    bool selectedX;
    double selectBeginX;
    double selectEndX;
    //移动
    bool moveX;//移动X轴
    //展开
    bool anX;//展开X轴
    //标志线
    double markLineX;
    //选取段
    QList<MarkBand> markBandList;


    QPoint beginPos,nowPos,endPos; //鼠标位置
//==============================================内部线程相关
public:
    void setFileParam(const AudioFileParam &value);
    void setDrawing(bool value);
    void setMarkBandList(const QList<MarkBand> &value);
    bool getSetleveled() const;

    QMap<double, QColor> getColorMap() const;
    void setColorMap(const QMap<double, QColor> &value);

private:
    //画图线程
    bool drawing;//正在绘制
    bool drawViewThreadRun;
    std::thread drawViewThread;//画图线程
    void drawView();//绘制处理

    //重画请求处理线程
    void addDrawRequest();
    QMutex drawRequestQueueMutex;
    QQueue<int> drawRequestQueue;//重绘请求队列
    bool queueDisposeThreadRun;
    std::thread queueDisposeThread;//队列处理线程
    void drawRequestQueueDispose();//请求队列处理线程

    //文件相关参数
    bool setfileParamed;//设置文件参数完成
    AudioFileParam fileParam;
//==============================================内部线程相关
private:
    void paintBg(QPainter &p);//画背景颜色
    void paintLineX(QPainter &p);//画网格
    void paintValueX(QPainter &p);
    void paintSpectrogram(QPainter &p);
    void paintAnX(QPainter &p);//X轴框选条
//    void paintLevel(QPainter &p);//画电平
//    void paintWaveVal(QPainter &p);//画波形刻度
//    void paintFreq(QPainter &p);//画频率

//    void paintFulls(QPainter &p);//画瀑布图
//    void paintFullsGradient(QPainter &p);//画瀑布图的渐变色系图
//    void paintWave(QPainter &p);//画时域
//    void paintIndex(QPainter &p);//画下标
      void paintSelectX(QPainter &p);//画框选
      void paintMarkLineX(QPainter &p);
      void paintMarkBand(QPainter &p);
//    void paintSubLine(QPainter &p);//画提示
//    void paintMarker(QPainter &p);//画Marker
//    void paintMeasureLine(QPainter &p);//画测量线
//    void paintHover(QPainter &p);
//    void paintFPS(QPainter &p);
protected:
    void mousePressEvent(QMouseEvent *event) override;    //鼠标按下事件
    void mouseMoveEvent(QMouseEvent *event) override;     //鼠标移动事件
    void mouseReleaseEvent(QMouseEvent *event) override;  //鼠标释放事
    void paintEvent(QPaintEvent *event) override;          //重绘事件
    void wheelEvent(QWheelEvent* event) override;     //滑轮滚动事件
    void keyPressEvent(QKeyEvent *event) override;   //键盘按下事件
    void keyReleaseEvent(QKeyEvent *event) override; //键盘松开事件
    void enterEvent(QEvent *event) override;
    void leaveEvent(QEvent *event) override;
    void mouseDoubleClickEvent(QMouseEvent *event) override;
    void resizeEvent(QResizeEvent *event) override;
};

#endif // SPECTROGRAMVIEW_H
